import bisect


class _KeyWrapper:
    def __init__(self, obj, key, reverse):
        self.obj = obj
        self.key = key
        self.reverse = reverse
    def __lt__(self, other):
        if self.reverse:
            return self.key(self.obj) > self.key(other.obj)
        else:
            return self.key(self.obj) < self.key(other.obj)
    def __eq__(self, other):
        return self.key(self.obj) == self.key(other.obj)


def bisect_left(sorted_data, target, key=None, reverse=False):
    """Return the leftmost index where to insert item x in list a, assuming a is sorted."""
    if key is None:
        key = lambda x: x
    wrapped_data = [_KeyWrapper(item, key, reverse) for item in sorted_data]
    wrapped_target = _KeyWrapper(target, key, reverse)
    index = bisect.bisect_left(wrapped_data, wrapped_target)
    return index


def bisect_right(sorted_data, target, key=None, reverse=False):
    """Return the rightmost index where to insert item x in list a, assuming a is sorted."""
    if key is None:
        key = lambda x: x
    wrapped_data = [_KeyWrapper(item, key, reverse) for item in sorted_data]
    wrapped_target = _KeyWrapper(target, key, reverse)
    index = bisect.bisect_right(wrapped_data, wrapped_target)
    return index
